package com.baymax.test.scene.view;

import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AccelerateDecelerateInterpolator;

import androidx.appcompat.widget.AppCompatImageView;

import com.baymax.test.scene.R;

public class BreathImage extends AppCompatImageView {
    public static final int NO_BREATH_VALUE = 0xbf;
    public static final int START_VALUE = 255;
    public static final int END_VALUE = 100;
    //是否开启呼吸灯
    protected boolean enableBreath;
    //是否允许绘制呼吸，开启但可以不绘制
    protected boolean allowBreath;
    //仅仅绘制呼吸灯但没有动画
    public boolean drawBreath;
    //特殊焦点的呼吸灯
    protected boolean specialBreath;
    //没有呼吸的呼吸灯
    protected boolean isNoBreathImage;
    //外围光环画笔
    private Paint shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    //搭边画笔
    private Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    //呼吸灯外围光环半径
    private float radius;
    //呼吸灯边框大小
    private float border;
    //呼吸灯圆角半径
    private float corner;
    //图片的padding
    private float padding;
    //呼吸灯外围光环矩形区域
    private RectF rectF;
    //呼吸灯边框的矩形区域
    private RectF borderRectF;
    private RectF clipRect;
    //呼吸灯外围光环矩形路径
    private Path path;
    //呼吸灯边框的矩形路径
    private Path borderPath;
    //颜色渐变器
    private ArgbEvaluator evaluator;
    //加速模式
    private int layerType = LAYER_TYPE_NONE;
    //呼吸灯动画对象
    private ValueAnimator animator;
    //特殊焦点图
    private Drawable specialDrawable;



    /**
     * 初始化各个参数，画笔等
     */ {
        Resources resources = getResources();
        radius = resources.getDimension(R.dimen.px18);
        border = resources.getDimension(R.dimen.px6);
        corner = resources.getDimension(R.dimen.px6);
        padding = resources.getDimension(R.dimen.px8);

        shadowPaint.setColor(Color.GREEN);
        shadowPaint.setMaskFilter(new BlurMaskFilter(radius, BlurMaskFilter.Blur.OUTER));

        borderPaint.setColor(Color.WHITE);
        borderPaint.setAntiAlias(true);
        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setStrokeWidth(border);


        rectF = new RectF();
        borderRectF = new RectF();

        path = new Path();
        borderPath = new Path();

        evaluator = new ArgbEvaluator();

        clipRect = new RectF();

    }

    public BreathImage(Context context) {
        super(context);
    }

    public BreathImage(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BreathImage(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        float offset = border - padding;

        //设置外围光环的路径和绘制区域大小
        path.reset();
        rectF.set(-offset, -offset, w + offset, h + offset);
        path.addRoundRect(rectF, new float[]{corner, corner, corner, corner, corner, corner, corner, corner}, Path.Direction.CW);

        //设置边框的路径和绘制区域大小
        borderPath.reset();
        borderRectF.set(-offset, -offset, w + offset, h + offset);
        borderPath.addRoundRect(borderRectF, new float[]{corner, corner, corner, corner, corner, corner, corner, corner}, Path.Direction.CW);


        clipRect.set( -100  ,-100 ,w + 100 , h + 100);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //仅仅绘制呼吸灯，无动画渐变效果
        if (drawBreath) {
            doDraw(canvas);
            drawBreath = false;
            return;
        } else {
            //允许绘制呼吸灯并且不是特殊焦点
            doDraw(canvas);
        }
    }

    private void doDraw(Canvas canvas){
        //允许绘制呼吸灯并且不是特殊焦点
        if (allowBreath && !specialBreath) {
            canvas.save();
            canvas.clipRect(clipRect);
            drawShadow(canvas);
            drawBorder(canvas);
            canvas.restore();

        }
    }


    /**
     * 绘制外围光环阴影
     *
     * @param canvas
     */
    private void drawShadow(Canvas canvas) {
        canvas.drawPath(path, shadowPaint);
    }

    /**
     * 描边
     *
     * @param canvas
     */
    private void drawBorder(Canvas canvas) {
        canvas.drawPath(borderPath, borderPaint);
    }

    /**
     * 启动呼吸动画
     * 通过动画插值器的变化值
     * 结合颜色渐变器更画笔的透明度
     * 反复绘制呼吸灯
     * 从而实现呼吸灯效果
     * 非特殊焦点
     */
    public void breath() {
        stopBreath();
        setLayer();
        allowBreath = true;
        if (isNoBreathImage) {
            return;
        }
        animator = ObjectAnimator.ofFloat(1f, 0.4f);
        animator.setDuration(1500);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.addUpdateListener(animation -> {
            float fraction = animation.getAnimatedFraction();
            int evaluate = (int) evaluator.evaluate(fraction, START_VALUE, END_VALUE);
            shadowPaint.setAlpha(evaluate);
            borderPaint.setAlpha(evaluate);
            postInvalidate();

        });
        animator.start();
    }

    /**
     * 停止呼吸灯
     * 结束呼吸灯动画
     */
    public void stopBreath() {
        //如果是特殊焦点，进行标志重置，特殊焦点背景重置
        if (specialBreath) {
            specialBreath = false;
            specialDrawable = null;
        } else {
            //重置硬件加速模式
            resetLayer();
        }
        allowBreath = false;
        //退出呼吸灯动画
        if (animator != null) {
            animator.cancel();
            animator = null;
            postInvalidate();
        }
    }

    /**
     * 禁用硬件加速
     * 记录之前的加速模式
     * 用于后面恢复
     * 同时设置不允许剪裁
     */
    private void setLayer() {
        View v = (View) getParent();
        if (v != null) {
            layerType = v.getLayerType();
            if (v.getLayerType() != LAYER_TYPE_SOFTWARE) {
                v.setLayerType(LAYER_TYPE_SOFTWARE, null);
            }

        }
        ViewParent parent = this.getParent();
        if (parent instanceof  ViewGroup){
            ((ViewGroup) parent).setClipChildren(false);
            ((ViewGroup) parent).setClipToPadding(false);
        }

    }

    /**
     * 还原硬件加速模式
     */
    private void resetLayer() {
        View v = (View) getParent();
        if (layerType >= 0) {
            v.setLayerType(layerType, null);
            layerType = -1;
        }
    }

    /**
     * 设置呼吸灯的颜色
     *
     * @param breathColor 颜色编码 #FFFFFF或#FFFFFFFF
     */
    public void setBreathColor(String breathColor) {
        try {
            int color = Color.parseColor(breathColor);
            shadowPaint.setColor(color);
            borderPaint.setColor(color);
        } catch (Exception e) {
            e.printStackTrace();
            shadowPaint.setColor(Color.WHITE);
            borderPaint.setColor(Color.WHITE);
        }
    }
    /**
     * 设置呼吸灯的颜色
     *
     * @param width 呼吸灯边框宽度
     * @param radius 呼吸灯圆角
     */
    public void setBreathWidthAndRadius(int width, int radius) {
        try {
            borderPaint.setStrokeWidth(width);
            border = width;
            corner = radius;
        } catch (Exception e) {
            e.printStackTrace();
            borderPaint.setStrokeWidth(border);
        }
    }

    /**
     * @method: changeBreathPadding
     * @description:
     * <p>
     * 根据外部的布局差值变化修改padding
     * </p>
     *
     * @param difference
     * @return void
     * @date: 2022/6/2 16:00
     * @author: baogh
     */
    public void changeBreathPadding(int difference) {
        padding = padding - difference;
    }

    /**
     * 绘制呼吸灯
     *
     * @return
     */
    public boolean drawBreath() {
        stopBreath();
        setLayer();
        if (isNoBreathImage) {
            shadowPaint.setAlpha(NO_BREATH_VALUE);
        } else {
            shadowPaint.setAlpha(START_VALUE);
        }
        borderPaint.setAlpha(START_VALUE);
        allowBreath = true;
        drawBreath = true;
        postInvalidate();
        return true;
    }

    /**
     * 配置是否开启呼吸灯功能
     *
     * @param enableBreath
     */
    public void configBreath(boolean enableBreath) {
        this.enableBreath = enableBreath;
    }

    /**
     * @method: configNoBreathImage
     * @description:
     * <p>
     * 配置是否是没有呼吸的呼吸灯
     * </p>
     *
     * @param isNoBreathImage
     * @return void
     * @date: 2022/5/31 18:20
     * @author: baogh
     */
    public void configNoBreathImage(boolean isNoBreathImage) {
        this.isNoBreathImage = isNoBreathImage;
    }

    /**
     * 是否支持呼吸灯
     *
     * @return
     */
    public boolean isEnableBreath() {
        return enableBreath;
    }

    /**
     * 特殊焦点的呼吸灯，通过变更特殊焦点的透明度实现呼吸效果
     *
     * @param drawable 特殊焦点图
     * @param v        加载特殊焦点的控件
     */
    public void startSpecialBreath(Drawable drawable, View v) {
        if (drawable == null) return;
        specialBreath = true;
        if (isNoBreathImage) {
            return;
        }
        animator = ObjectAnimator.ofFloat(1f, 0.4f);
        animator.setDuration(1500);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.addUpdateListener(animation -> {
            float fraction = animation.getAnimatedFraction();
            int evaluate = (int) evaluator.evaluate(fraction, START_VALUE, END_VALUE);
            if (specialDrawable != null) {
                specialDrawable.setAlpha(evaluate);
            }
            if (evaluate < END_VALUE + 5) {
                if (specialDrawable == null) {
                    this.specialDrawable = drawable;
                    v.setBackground(specialDrawable);
                }
            }
            if (specialDrawable != null) {
                postInvalidate();
            }
        });
        animator.start();
    }

}